package com.shop.cloud.upms.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shop.cloud.common.core.constant.CacheConstants;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.core.constant.SecurityConstants;
import com.shop.cloud.common.data.shardingtable.config.ShardingTableProperties;
import com.shop.cloud.common.data.tenant.TenantContextHolder;
import com.shop.cloud.common.security.entity.BaseUser;
import com.shop.cloud.common.security.util.SecurityUtils;
import com.shop.cloud.common.sms.config.SmsConfigProperties;
import com.shop.cloud.common.sms.util.SmsUtils;
import com.shop.cloud.mall.common.feign.FeignGoodsSpuService;
import com.shop.cloud.mall.common.feign.FeignShardingDataBaseService;
import com.shop.cloud.upms.admin.mapper.SysTenantMapper;
import com.shop.cloud.upms.admin.service.*;
import com.shop.cloud.upms.common.entity.*;
import com.shop.cloud.upms.common.feign.FeignConfigSmsService;
import com.shop.cloud.weixin.common.feign.FeignWxUserService;
import lombok.AllArgsConstructor;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 租户管理
 *
 * @author
 */
@Service
@AllArgsConstructor
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant> implements SysTenantService {

	private final SysUserService sysUserService;
	private final SysRoleService sysRoleService;
	private final SysUserRoleService sysUserRoleService;
	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
	private final FeignConfigSmsService feignConfigSmsService;
	private final SysRoleMenuService sysRoleMenuService;
	private final SysTenantPackageMenuService sysTenantPackageMenuService;
	private final CacheManager cacheManager;

	private final FeignShardingDataBaseService feignShardingDataBaseService;
	private final ShardingTableProperties shardingTableProperties;
	private final FeignWxUserService feignWxUserService;
	private final FeignGoodsSpuService feignGoodsSpuService;
	private final SysUserTenantService sysUserTenantService;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean save(SysTenant entity) {
		baseMapper.insert(entity);
		//新建租户管理员用户
		SysUser sysUser = new SysUser();
		sysUser.setUsername(entity.getUsername());
		sysUser.setPassword(ENCODER.encode(entity.getPassword()));
		sysUser.setPhone(entity.getUserPhone());
		sysUser.setType(CommonConstants.USER_TYPE_1);
		sysUserService.save(sysUser);
		//新建租户管理员角色
		SysRole sysRole = new SysRole();
		sysRole.setRoleName("租户管理员");
		sysRole.setRoleCode(CommonConstants.ROLE_CODE_ADMIN);
		sysRole.setRoleDesc(entity.getName()+"租户管理员");
		sysRole.setDsType(CommonConstants.DS_TYPE_0);
		sysRoleService.save(sysRole);
		//新建店铺管理员角色
		SysRole sysRole2 = new SysRole();
		sysRole2.setRoleName("店铺管理员");
		sysRole2.setRoleCode(CommonConstants.ROLE_CODE_SHOP_USER);
		sysRole2.setRoleDesc(entity.getName()+"店铺管理员，新增店员时授权的默认角色");
		sysRole2.setDsType(CommonConstants.DS_TYPE_0);
		sysRoleService.save(sysRole2);
		//新建用户角色
		SysUserRole sysUserRole = new SysUserRole();
		sysUserRole.setRoleId(sysRole.getId());
		sysUserRole.setUserId(sysUser.getId());
		sysUserRoleService.save(sysUserRole);
		//将该租户关联到当前用户
		BaseUser baseUser = SecurityUtils.getUser();
		if(StrUtil.equals(CommonConstants.USER_TYPE_S, baseUser.getType())){
			SysUserTenant sysUserTenant = new SysUserTenant();
			sysUserTenant.setUserId(baseUser.getId());
			sysUserTenant.setTenantId(entity.getId());
			sysUserTenantService.save(sysUserTenant);
		}
		//初始化租户数据库
		this.initTenantDataBase(entity.getId());
		//初始化ES商品
		feignGoodsSpuService.esInitInside(entity.getId(),  SecurityConstants.FROM_IN);
		//有选租户套餐则同步套餐权限
		if(StrUtil.isNotBlank(entity.getPackageId())){
			this.syncTenantPackage(entity.getId());
		}
		if(StrUtil.isNotBlank(sysUser.getPhone())){
			try{
				//发送短信通知
				Map map = new HashMap<>();
				map.put("mallName", entity.getName());
				map.put("userName", sysUser.getUsername());
				map.put("userPassword", entity.getPassword());
				//取系统平台短信配置
				TenantContextHolder.setTenantId(CommonConstants.SYSTEM_TENANT_ID);
				SysConfigSms sysConfigSms = feignConfigSmsService.getSysConfigSms(SecurityConstants.FROM_IN).getData();
				if(sysConfigSms == null){
					throw new RuntimeException("未配置短信账号");
				}
				SysConfigSmsTemplates sysConfigSmsTemplates = JSONUtil.toBean(sysConfigSms.getTemplates(),SysConfigSmsTemplates.class);
				SmsConfigProperties smsConfigProperties = new SmsConfigProperties();
				BeanUtil.copyProperties(sysConfigSms, smsConfigProperties);
				SmsUtils.sendSms(smsConfigProperties,
						sysConfigSmsTemplates.getSignName10(),
						sysUser.getPhone(),
						sysConfigSmsTemplates.getTemplateCode10(),
						JSONUtil.toJsonStr(map)
				);
			}catch (Exception e){
				log.error(e.getMessage());
			}
		}
		return Boolean.TRUE;
	}

	@Override
	@Cacheable(value = CacheConstants.UPMS_TENANT, key = "#id")
	public SysTenant getById(Serializable id) {
		return super.getById(id);
	}

	@Override
	@CacheEvict(value = CacheConstants.UPMS_TENANT, key = "#entity.id")
	public boolean updateById(SysTenant entity) {
		return super.updateById(entity);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@CacheEvict(value = CacheConstants.UPMS_TENANT, key = "#id")
	public boolean removeById(Serializable id) {
		baseMapper.deleteSysTenantById(id);
		return Boolean.TRUE;
	}

	@Override
	public List<SysTenant> listSysTenant(String userId) {
		return baseMapper.listSysTenant(userId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void initTenantDataBase(String tenantId) {
		//获取商城模块基础数据库名
		TenantContextHolder.setTenantId(null);
		String dbNameMall = feignShardingDataBaseService.getShardingDataBasePropertiesDbname(SecurityConstants.FROM_IN).getData();
		TenantContextHolder.setTenantId(tenantId);
		//获取商城模块基础数据库的所有表名
		List<String> dataBaseTables = baseMapper.listDataBaseTables(dbNameMall);
		//根据商城模块基础数据库新增指定租户的库和表
		baseMapper.createTenantDataBase(tenantId, dataBaseTables, dbNameMall);

		//初始化upms模块的租户分表
		this.createTenantDataBaseTables(tenantId);

		//初始化wx模块的租户分表
		feignWxUserService.createTenantDataBaseTables(tenantId, SecurityConstants.FROM_IN);
	}

	void createTenantDataBaseTables(String tenantId){
		//获取需分表的表名
		List<String> shardingTables = shardingTableProperties.getTables();
		//新增指定租户的表
		baseMapper.createTenantDataBaseTables(tenantId, shardingTables);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean syncTenantPackage(String tenantId) {
		TenantContextHolder.setTenantId(tenantId);
		//清空该租户下的角色所有菜单权限
		sysRoleMenuService.remove(Wrappers.<SysRoleMenu>lambdaQuery().eq(SysRoleMenu::getTenantId, tenantId));
		//查出套餐的菜单ids
		SysTenantPackageMenu sysTenantPackageMenu = sysTenantPackageMenuService.getById(this.getById(tenantId).getPackageId());
		if(sysTenantPackageMenu == null){
			return Boolean.TRUE;
		}
		String[] menuIds = sysTenantPackageMenu.getMenuIds();
		if(menuIds.length == 0){
			return Boolean.TRUE;
		}
		//查出该租户的管理员角色
		SysRole sysRole = sysRoleService.getOne(Wrappers.<SysRole>lambdaQuery()
				.eq(SysRole::getRoleCode, CommonConstants.ROLE_CODE_ADMIN)
				.eq(SysRole::getTenantId, tenantId));
		List<SysRoleMenu> roleMenuList = Arrays.stream(menuIds).toList().stream()
				.map(menuId -> {
					SysRoleMenu roleMenu = new SysRoleMenu();
					roleMenu.setRoleId(sysRole.getId());
					roleMenu.setMenuId(menuId);
					return roleMenu;
				}).collect(Collectors.toList());

		//清空缓存
		cacheManager.getCache(CacheConstants.USER_CACHE).clear();
		cacheManager.getCache(CacheConstants.MENU_CACHE).clear();
		return sysRoleMenuService.saveBatch(roleMenuList);
	}
}
